#include "qmaincore.h"

void QMainCore::findBoundaryElements(void)
{
    for (int i=0; i<cell.nodes.length(); ++i)
    {
        cell.nodes[i].id1 = -1;
        cell.nodes[i].id2 = -1;
    }

    for (int i=0; i<cell.edges.length(); ++i)
    {
        if (cell.nodes[cell.edges[i].id1].isBoundary && cell.nodes[cell.edges[i].id2].isBoundary)
        {
            cell.edges[i].isBoundary = true;

            (cell.nodes[cell.edges[i].id1].id1 < 0) ?
                    cell.nodes[cell.edges[i].id1].id1 = cell.edges[i].id2 :
                                                        cell.nodes[cell.edges[i].id1].id2 = cell.edges[i].id2;

            (cell.nodes[cell.edges[i].id2].id1 < 0) ?
                    cell.nodes[cell.edges[i].id2].id1 = cell.edges[i].id1 :
                                                        cell.nodes[cell.edges[i].id2].id2 = cell.edges[i].id1;
        }
    }
}

void QMainCore::calculateAreas(void)
{
    /*     /\ C
          /  \
        b/    \a
        /      \
     A ---------- B
            c

     shift B and C by A: B_new = B_old - A, C_new = C_old - A;
     i.e. A is new 'zero point (0,0)'*/


    for (int i=0; i<cell.edges.length(); ++i)
    {
        A = cell.nodes[cell.edges[i].id1].pos;
        B = cell.nodes[cell.edges[i].id2].pos;
        C = cell.nodes[cell.edges[i].id3].pos;

        a = distance(B, C);
        b = distance(C, A);
        c = distance(B, A);

        O = (a*A+b*B+c*C)/(a+b+c) - A;
        N = B - A;

        cell.edges[i].currentArea = qAbs(O.x()*N.y() - O.y()*N.x())/2; // half of the parallelogram area

        if (cell.edges[i].id4>=0)  // additional area for non-boundary edges
        {
            C = cell.nodes[cell.edges[i].id4].pos;
            a = distance(B, C);
            b = distance(C, A);

            O = (a*A+b*B+c*C)/(a+b+c) - A;
            N = B - A;

            cell.edges[i].currentArea += qAbs(O.x()*N.y() - O.y()*N.x())/2;
        }

        if (cell.edges[i].area < 0) cell.edges[i].area = cell.edges[i].currentArea;
    }
}

void QMainCore::calculateEdgesRigidity(void)
{
    double x[cell.edges.length()];

    alpha = atan2((cell.fCPos-cell.cPos).y(), (cell.fCPos-cell.cPos).x());

    for (int i=0; i<cell.edges.length(); ++i)
    {
        cell.edges[i].pos = (cell.nodes[cell.edges[i].id1].pos + cell.nodes[cell.edges[i].id2].pos)/2;
        x[i] = cell.edges[i].pos.x()*cos(alpha) + cell.edges[i].pos.y()*sin(alpha);
    }

    xMin = *std::min_element(x, x+cell.edges.length());
    xMax = *std::max_element(x, x+cell.edges.length());

    xMax -= xMin;

    for (int i=0; i<cell.edges.length(); ++i)
    {
        if (cell.edges[i].area < 0) this->calculateAreas();
        x[i] -= xMin;
        // \kappa = \frac{S*h*E}{L^2} - Hookean coefficient
        cell.edges[i].kappa = cell.edges[i].area * cell.h / pow(distance(cell.nodes[cell.edges[i].id1].pos, cell.nodes[cell.edges[i].id2].pos),2) *
                              (cell.eMin + (cell.eMax - cell.eMin)*(1-1/(1+exp(0.05*(x[i] - xMax/2)))));
        //qDebug() << x[i] << "\t" << (cell.eMin + (cell.eMax - cell.eMin)*(1-1/(1+exp(0.05*((x[i]-xmin) - (xmax-xmin)/2)))));
    }
}

void QMainCore::findCenterAndFrontCenterPoses(void)
{
    cell.fCPos = QPointF(0,0);
    cell.frontNodesCount = 0;
    tempCPos = cell.cPos;
    cell.cPos = QPointF(0,0);

    for (int i=0; i<cell.nodes.length(); ++i)
    {
        cell.cPos += cell.nodes[i].pos;
        if (cell.nodes[i].isFrontal)
        {
            cell.fCPos += cell.nodes[i].pos;
            cell.frontNodesCount++;
        }
        if (cell.nodes[i].isBoundary) cell.boundaryNodesCount++;
    }

    cell.cPos = cell.cPos/cell.nodes.length();

    if (cell.frontNodesCount>0)
    {
        cell.fCPos = cell.fCPos/cell.frontNodesCount;

        if (!(static_cast<int>(cell.t/cell.dt)%100))
        {
            cell.fCPosPolygon << cell.fCPos;
        }
    }

    cell.velocity = 60*distance(cell.cPos-tempCPos)/cell.scale/cell.dt;

    /***Cell Velocity***/ //!!add global v to proceed
    //    if (cell.t < 1) v = 0;
    //    if (cell.t > 50) v+=cell.velocity;
    //    if (cell.t > 100) {
    //        cell.t = 0;
    //        qDebug() << cell.sigma << "\t" << v/500;
    //        cell.sigma += 10e4;
    //    }


    /***Cell Area***/
    //    if (cell.t > 1000) {
    //        cell.t = 0;
    //        cell.area = 0;

    //        this->calculateAreas();
    //        for (int i=0; i<cell.edges.length(); ++i) cell.area += cell.edges[i].currentArea;

    //        qDebug() << cell.sigma << "\t" << cell.area/pow(cell.scale,2);
    //        cell.sigma += 1e4;
    //    }
}

void QMainCore::calculateNodesPositions(void)
{
    if (cell.nodes.length()>5)
    {
        this->findCenterAndFrontCenterPoses();

        if (cell.boundaryNodesCount)
        {

            if (cell.fCPosPolygon.count() > 5e3) cell.fCPosPolygon.clear();

            dir = QPointF(0,0);

            for (int i=0; i<cell.nodes.length(); ++i)
            {
                dir += QPointF(cell.nodes[i].fx, cell.nodes[i].fy);

                if (trackAdh||trackPol||trackCon||trackEla)  // Monitor
                {
                    cell.nodes[i].fxMonitor = 0;
                    cell.nodes[i].fyMonitor = 0;
                }
            }

            /***** Frontal nodes rotation *****/

            if (static_cast<int>(floor(10*cell.t))%600 == 0)
            {
                //if (false) {
                id1 = -1;
                id2 = -1;

                for (int i=0; i<cell.nodes.length(); ++i)
                {
                    if ((cell.nodes[i].isFrontal) &&
                        ((cell.nodes[cell.nodes[i].id1].isFrontal && !cell.nodes[cell.nodes[i].id2].isFrontal) ||
                         (!cell.nodes[cell.nodes[i].id1].isFrontal && cell.nodes[cell.nodes[i].id2].isFrontal)))
                    {
                        (id1<0) ? id1 = i : id2 = i;
                    }
                }

                if ((id1>=0)&&(id2>=0))
                {

                    if (cosine(dir, cell.nodes[id1].pos-cell.cPos) > cosine(dir, cell.nodes[id2].pos-cell.cPos))
                    {
                        cell.nodes[id2].isFrontal = false;

                        (cell.nodes[cell.nodes[id1].id1].isFrontal) ? id1 = cell.nodes[id1].id2 : id1 = cell.nodes[id1].id1;
                    }
                    else
                    {
                        cell.nodes[id1].isFrontal = false;

                        (cell.nodes[cell.nodes[id2].id1].isFrontal) ? id2 = cell.nodes[id2].id2 : id2 = cell.nodes[id2].id1;
                    }

                    if (cosine(dir, cell.nodes[id1].pos-cell.cPos) < cosine(dir, cell.nodes[id2].pos-cell.cPos))
                    {
                        cell.nodes[id2].isFrontal = true;
                    }
                    else
                    {
                        cell.nodes[id1].isFrontal = true;
                    }

                    this->findCenterAndFrontCenterPoses();
                    this->calculateEdgesRigidity();
                }
            }

            /***** Adhesion force block *****/
            double xNodes[cell.nodes.length()];


            p = cell.fCPos-cell.cPos;
            alpha = atan2(p.y(), p.x());

            for (int i=0; i<cell.nodes.length(); ++i)
            {
                xNodes[i] = (cell.nodes[i].pos-cell.cPos).x()*cos(alpha) + (cell.nodes[i].pos-cell.cPos).y()*sin(alpha);
            }

            xMin = *std::min_element(xNodes, xNodes+cell.nodes.length()-1);
            xMax = *std::max_element(xNodes, xNodes+cell.nodes.length()-1);

            xMax -= xMin;

            sum = 0;


            for (int i=0; i<cell.nodes.length(); ++i)
            {
                xNodes[i] -= xMin;
                sum += exp(- (xMax - xNodes[i])/(cell.gamma*xMax));
            }

            q = cell.fadh*cell.nodes.length()/sum;

            for (int i=0; i<cell.nodes.length(); ++i)
            {
                cell.nodes[i].sigma = cell.sigma;

                for (int j=0; j<cell.areas.length(); ++j)
                {
                    if(cell.areas[j].rect.contains(cell.nodes[i].pos)) cell.nodes[i].sigma += cell.areas[j].sigma;
                }

                p = cell.nodes[i].adhesionPos - cell.nodes[i].pos;
                l = distance(p);
                alpha = atan2(p.y(),p.x());

                f = q*exp(- (xMax - xNodes[i])/(cell.gamma*xMax))*(cell.nodes[i].sigma/cell.sigmaAV);
                fx = f*cos(alpha)*((l/cell.scale)/1);
                fy = f*sin(alpha)*((l/cell.scale)/1);

                if ((sqrt(pow(fx,2)+pow(fy,2)) > f)||(cell.nodes[i].isFrontal))
                {
                    fx = 0;
                    fy = 0;
                    cell.nodes[i].adhesionPos = cell.nodes[i].pos;
                }

                cell.nodes[i].fx = fx;
                cell.nodes[i].fy = fy;

                if (trackAdh) // Monitor
                {
                    cell.nodes[i].fxMonitor += fx;
                    cell.nodes[i].fyMonitor += fy;
                }

                /***** Polymerization force block *****/
                if (cell.nodes[i].isFrontal)
                {
                    A = cell.nodes[i].pos;
                    B = cell.nodes[cell.nodes[i].id1].pos;
                    C = cell.nodes[cell.nodes[i].id2].pos;

                    a = distance(B, C);
                    b = distance(A, C);
                    c = distance(A, B);

                    bisectorCrossPoint = (a*A+b*B+c*C)/(a+b+c);

                    p = cell.nodes[i].pos - bisectorCrossPoint;
                    alpha = atan2(p.y(),p.x());

                    //Directions switcher
                    testPoint = A + QPointF(cos(alpha), sin(alpha));

                    for (int j=0; j<cell.edges.length(); ++j)
                    {
                        if (cell.edges[j].isBoundary)
                        {
                            if (((cell.nodes[cell.edges[j].id1].pos.y() <= testPoint.y())&&(cell.nodes[cell.edges[j].id2].pos.y() >= testPoint.y()))||
                                ((cell.nodes[cell.edges[j].id1].pos.y() >= testPoint.y())&&(cell.nodes[cell.edges[j].id2].pos.y() <= testPoint.y())))
                            {
                                if (qMin(cell.nodes[cell.edges[j].id1].pos.x(), cell.nodes[cell.edges[j].id2].pos.x()) >= testPoint.x())
                                {
                                    alpha += M_PI;
                                }
                            }
                        }
                    }

                    cell.nodes[i].fx += (cell.fpol*cell.nodes.length()/cell.frontNodesCount)*hillFunction(cell.nodes[i].sigma, cell.sigmaAV) * cos(alpha);
                    cell.nodes[i].fy += (cell.fpol*cell.nodes.length()/cell.frontNodesCount)*hillFunction(cell.nodes[i].sigma, cell.sigmaAV) * sin(alpha);

                    if (trackPol) // Monitor
                    {
                        cell.nodes[i].fxMonitor += (cell.fpol*cell.nodes.length()/cell.frontNodesCount)*hillFunction(cell.nodes[i].sigma, cell.sigmaAV) * cos(alpha);
                        cell.nodes[i].fyMonitor += (cell.fpol*cell.nodes.length()/cell.frontNodesCount)*hillFunction(cell.nodes[i].sigma, cell.sigmaAV) * sin(alpha);
                    }
                }
            }

            /***** Contractile force block *****/
            double xEdges[cell.edges.length()];

            p = cell.fCPos-cell.cPos;
            alpha = atan2(p.y(), p.x());

            for (int i=0; i<cell.edges.length(); ++i)
            {
                p = (cell.nodes[cell.edges[i].id1].pos+cell.nodes[cell.edges[i].id2].pos)/2;
                xEdges[i] = (p-cell.cPos).x()*cos(alpha) + (p-cell.cPos).y()*sin(alpha);
            }

            xMin = *std::min_element(xEdges, xEdges+cell.edges.length()-1);
            xMax = *std::max_element(xEdges, xEdges+cell.edges.length()-1);

            xMax -= xMin;

            sum = 0;

            for (int i=0; i<cell.edges.length(); ++i)
            {
                xEdges[i] -= xMin;

                /*** Lengths distribution ***/
                //        if(static_cast<int>(cell.t/cell.dt) == (30000))
                //            qDebug() << xEdges[i] << "\t" << distance(cell.nodes[cell.edges[i].id1].pos, cell.nodes[cell.edges[i].id2].pos)-cell.edges[i].defaultLength << "\t" << cell.edges[i].defaultLength;

                sum += exp(- (xMax - xEdges[i])/(cell.beta*xMax));
            }

            q = cell.fcon*cell.nodes.length()/sum;

            for (int i=0; i<cell.edges.length(); ++i)
            {
                if (cell.edges[i].kappa < 0) this->calculateEdgesRigidity();
                if (cell.edges[i].defaultLength < 0) this->resetDefaultLengths();

                cell.edges[i].sigma = cell.sigma;

                for (int j=0; j<cell.areas.length(); ++j)
                {
                    if (cell.areas[j].rect.contains((cell.nodes[cell.edges[i].id1].pos + cell.nodes[cell.edges[i].id2].pos)/2))
                        cell.edges[i].sigma += cell.areas[j].sigma;
                }

                fcon = q*exp(-(xMax - xEdges[i])/(cell.beta*xMax)) * hillFunction(cell.edges[i].sigma, cell.sigmaAV);

                /*** Contractile force distribution ***/
                //        if(static_cast<int>(cell.t/cell.dt) == (30000))
                //        qDebug() << x[i] << "\t" << fcon;

                p = cell.nodes[cell.edges[i].id2].pos - cell.nodes[cell.edges[i].id1].pos;
                alpha = atan2(p.y(), p.x());

                cell.nodes[cell.edges[i].id1].fx += fcon * cos(alpha);
                cell.nodes[cell.edges[i].id1].fy += fcon * sin(alpha);
                cell.nodes[cell.edges[i].id2].fx -= fcon * cos(alpha);
                cell.nodes[cell.edges[i].id2].fy -= fcon * sin(alpha);

                if (trackCon) // Monitor
                {
                    cell.nodes[cell.edges[i].id1].fxMonitor += fcon * cos(alpha);
                    cell.nodes[cell.edges[i].id1].fyMonitor += fcon * sin(alpha);
                    cell.nodes[cell.edges[i].id2].fxMonitor -= fcon * cos(alpha);
                    cell.nodes[cell.edges[i].id2].fyMonitor -= fcon * sin(alpha);
                }

                /***Viscosious force block***/

                /* ........... */

                /***** Elastic force block *****/
                p = cell.nodes[cell.edges[i].id2].pos - cell.nodes[cell.edges[i].id1].pos;
                l = distance(p);
                alpha = atan2(p.y(), p.x());

                cell.nodes[cell.edges[i].id1].fx += 1e-6*((l - cell.edges[i].defaultLength)/cell.scale * cell.edges[i].kappa) * cos(alpha);
                cell.nodes[cell.edges[i].id1].fy += 1e-6*((l - cell.edges[i].defaultLength)/cell.scale * cell.edges[i].kappa) * sin(alpha);
                cell.nodes[cell.edges[i].id2].fx -= 1e-6*((l - cell.edges[i].defaultLength)/cell.scale * cell.edges[i].kappa) * cos(alpha);
                cell.nodes[cell.edges[i].id2].fy -= 1e-6*((l - cell.edges[i].defaultLength)/cell.scale * cell.edges[i].kappa) * sin(alpha);

                if (trackEla) // Monitor
                {
                    cell.nodes[cell.edges[i].id1].fxMonitor += 1e-6*((l - cell.edges[i].defaultLength)/cell.scale * cell.edges[i].kappa) * cos(alpha);
                    cell.nodes[cell.edges[i].id1].fyMonitor += 1e-6*((l - cell.edges[i].defaultLength)/cell.scale * cell.edges[i].kappa) * sin(alpha);
                    cell.nodes[cell.edges[i].id2].fxMonitor -= 1e-6*((l - cell.edges[i].defaultLength)/cell.scale * cell.edges[i].kappa) * cos(alpha);
                    cell.nodes[cell.edges[i].id2].fyMonitor -= 1e-6*((l - cell.edges[i].defaultLength)/cell.scale * cell.edges[i].kappa) * sin(alpha);
                }
            }

            for (int i=0; i<cell.nodes.length(); ++i)
            {
                cell.nodes[i].pos += cell.scale*1E6*QPointF(cell.nodes[i].fx*cell.dt, cell.nodes[i].fy*cell.dt)/cell.mu;
            }

            if (!(static_cast<int>(cell.t/cell.dt)%5)) emit cellChanged(cell);
        }
        else this->stop();
    }
    else this->stop();
}

void QMainCore::run(void)
{
    stopped = false;

    while (!stopped)
    {
        this->calculateNodesPositions();
        cell.t+=cell.dt;
    }

    emit toggled();
}

QMainCore::QMainCore(QObject *parent) : QThread(parent)
{
    trackAdh = false;
    trackPol = false;
    trackCon = false;
    trackEla = false;
}

double QMainCore::distance(const QPointF& p1, const QPointF& p2)
{
    return sqrt(pow(p2.x()-p1.x(), 2) + pow(p2.y()-p1.y(), 2));
}

double QMainCore::hillFunction(double sigma, double sigmaAV)
{
    return pow(sigma, 2)/(pow(sigma, 2) + pow(sigmaAV, 2));
}

double QMainCore::cosine(const QPointF& p1, const QPointF& p2)
{
    return (p1.x()*p2.x()+p1.y()*p2.y())/(distance(p1)*distance(p2));
}

void QMainCore::stop(void)
{
    stopped = true;
    emit toggled();
}

void QMainCore::reset(void)
{
    cell.t = 0;
    this->stop();

    cell.fCPosPolygon.clear();

    cell.nodes.clear();
    cell.edges.clear();
    cell.areas.clear();

    emit cellChanged(cell);
}

void QMainCore::resetDefaultLengths(void)
{
    for (int i=0; i<cell.edges.length(); ++i)
    {
        cell.edges[i].defaultLength = distance(cell.nodes[cell.edges[i].id1].pos, cell.nodes[cell.edges[i].id2].pos);
    }
}

void QMainCore::resetAdhesionPoses(void)
{
    for (int i=0; i<cell.nodes.length(); ++i)
    {
        cell.nodes[i].adhesionPos= cell.nodes[i].pos;
    }
}

int QMainCore::getNearestNode(const QPointF& pos) const
{
    int id = -1;
    for (int i=0; i<cell.nodes.length(); ++i)
    {
        if (distance(cell.nodes[i].pos, pos) < 12)
        {
            if (id < 0) id = i;
            else if(distance(cell.nodes[i].pos,pos) < distance(cell.nodes[id].pos, pos)) id = i;
        }
    }
    return id;
}

int QMainCore::getNearestEdge(const QPointF& pos) const
{
    int id = -1;
    for (int i=0; i<cell.edges.length(); ++i)
    {
        if (distance((cell.nodes[cell.edges[i].id1].pos + cell.nodes[cell.edges[i].id2].pos)/2, pos) < 10)
        {
            if (id < 0) id = i;
            else if (distance((cell.nodes[cell.edges[i].id1].pos + cell.nodes[cell.edges[i].id2].pos)/2, pos) <
                     distance((cell.nodes[cell.edges[id].id1].pos + cell.nodes[cell.edges[id].id2].pos)/2, pos)) id = i;
        }
    }
    return id;
}

int QMainCore::getNearestArea(const QPointF& pos) const
{
    int id = -1;
    for (int i=0; i<cell.areas.length(); ++i)
    {
        if (distance((cell.areas[i].rect.topLeft()+cell.areas[i].rect.bottomRight())/2, pos)<30)
        {
            if (id < 0) id = i;
            else if (distance((cell.areas[i].rect.topLeft()+cell.areas[i].rect.bottomRight())/2, pos) <
                     distance((cell.areas[id].rect.topLeft()+cell.areas[id].rect.bottomRight())/2, pos)) id = i;
        }
    }
    return id;
}

void QMainCore::addNode(const QPointF &pos)
{
    if (this->getNearestNode(pos)<0)
    {
        NODE node;
        node.pos = pos;
        node.adhesionPos = pos;
        cell.nodes << node;

        emit cellChanged(cell);
    }
}

void QMainCore::addEdge(const QPointF &pos1, const QPointF &pos2)
{
    id1 = this->getNearestNode(pos1);
    id2 = this->getNearestNode(pos2);

    if ((id1>=0)&&(id2>=0)) this->addEdge(id1, id2);
}

void QMainCore::addEdge(const int id1, const int id2)
{
    id3 = -1;
    id4 = -1;

    unique = true;

    for (int i=0; i<cell.edges.length(); ++i)
    {
        if ((cell.edges[i].id1 == id1 && cell.edges[i].id2 == id2)||
            (cell.edges[i].id1 == id2 && cell.edges[i].id2 == id1))
            unique = false;

        for (int j=i+1; j<cell.edges.length(); ++j)
        {
            if (cell.edges[i].id1 == cell.edges[j].id1)
            {
                if (((cell.edges[i].id2 == id1)&&(cell.edges[j].id2 == id2))||((cell.edges[i].id2 == id2)&&(cell.edges[j].id2 == id1)))
                    (id3<0)? id3 = cell.edges[i].id1 : id4 = cell.edges[i].id1;
            }
            if (cell.edges[i].id1 == cell.edges[j].id2)
            {
                if (((cell.edges[i].id2 == id1)&&(cell.edges[j].id1 == id2))||((cell.edges[i].id2 == id2)&&(cell.edges[j].id1 == id1)))
                    (id3<0)? id3 = cell.edges[i].id1 : id4 = cell.edges[i].id1;
            }
            if (cell.edges[i].id2 == cell.edges[j].id1)
            {
                if (((cell.edges[i].id1 == id1)&&(cell.edges[j].id2 == id2))||((cell.edges[i].id1 == id2)&&(cell.edges[j].id2 == id1)))
                    (id3<0)? id3 = cell.edges[i].id2 : id4 = cell.edges[i].id2;
            }
            if (cell.edges[i].id2 == cell.edges[j].id2)
            {
                if (((cell.edges[i].id1 == id1)&&(cell.edges[j].id1 == id2))||((cell.edges[i].id1 == id2)&&(cell.edges[j].id1 == id1)))
                    (id3<0)? id3 = cell.edges[i].id1 : id4 = cell.edges[i].id1;
            }
        }
    }

    if (unique)
    {
        if ((id1>=0)&&(id2>=0))
        {
            EDGE edge;
            edge.id1 = id1;
            edge.id2 = id2;
            edge.id3 = id3;
            edge.id4 = id4;
            edge.defaultLength = distance(cell.nodes[id1].pos, cell.nodes[id2].pos);
            cell.edges << edge;
        }

        emit cellChanged(cell);
    }
}

void QMainCore::addArea(const QRectF &rect)
{
    if ((rect.width()+rect.height()) > 16)
    {
        AREA area;
        area.rect = rect;
        cell.areas << area;

        emit cellChanged(cell);
    }
}

CELL QMainCore::getCell(void) const
{
    return cell;
}

void QMainCore::setCell(const CELL &_cell)
{
    cell = _cell;
    this->resetAdhesionPoses();
    this->findBoundaryElements();
    this->findCenterAndFrontCenterPoses();
    this->calculateEdgesRigidity();

    emit cellChanged(cell);
}

void QMainCore::setModelPos(int id, const QPointF &pos)
{
    cell.fCPosPolygon.clear();

    for (int i=0; i<cell.nodes.length(); ++i)
    {
        if (i!=id) cell.nodes[i].pos = cell.nodes[i].pos + (pos-cell.nodes[id].pos);
    }
    cell.nodes[id].pos = pos;

    this->resetAdhesionPoses();

    emit cellChanged(cell);
}

void QMainCore::setNodePos(int id, const QPointF &pos)
{
    if (cell.nodes[id].isFrontal)
        cell.fCPosPolygon.clear();
    cell.nodes[id].pos = pos;

    emit cellChanged(cell);
}

void QMainCore::setAreaPos(int id, const QPointF &pos)
{
    cell.areas[id].rect = QRect(pos.x()-cell.areas[id].rect.width()/2,pos.y()-cell.areas[id].rect.height()/2,
                                cell.areas[id].rect.width(), cell.areas[id].rect.height());

    emit cellChanged(cell);
}

void QMainCore::toggleNodeBoundary(const QPointF pos)
{
    id = this->getNearestNode(pos);

    if (id >=0)
    {
        if(!cell.nodes[id].isBoundary) cell.nodes[id].isBoundary = true;
        else cell.nodes[id].isBoundary = false;
        this->findBoundaryElements();
    }

    emit cellChanged(cell);
}

void QMainCore::toggleNodeFrontal(const QPointF pos)
{
    id = this->getNearestNode(pos);

    if (id >=0)
    {
        if(!cell.nodes[id].isFrontal && cell.nodes[id].isBoundary)
            cell.nodes[id].isFrontal = true;
        else cell.nodes[id].isFrontal = false;
    }

    emit cellChanged(cell);
}

void QMainCore::setTrackAdh(bool _trackAdh)
{
    trackAdh = _trackAdh;
}

void QMainCore::setTrackPol(bool _trackPol)
{
    trackPol = _trackPol;
}

void QMainCore::setTrackCon(bool _trackCon)
{
    trackCon = _trackCon;
}

void QMainCore::setTrackEla(bool _trackEla)
{
    trackEla = _trackEla;
}
